// import * as THREE from 'three/build/three.module.js';
import * as THREE from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
import { RGBELoader } from 'three/examples/jsm/loaders/RGBELoader.js';
import { GLTFLoader, GLTF } from 'three/examples/jsm/loaders/GLTFLoader.js'
import { EffectComposer } from 'three/examples/jsm/postprocessing/EffectComposer.js';
import { RenderPass } from 'three/examples/jsm/postprocessing/RenderPass.js';
import { ShaderPass } from 'three/examples/jsm/postprocessing/ShaderPass.js';
import { OutlinePass } from 'three/examples/jsm/postprocessing/OutlinePass.js';
import { FXAAShader } from 'three/examples/jsm/shaders/FXAAShader.js';
import { OBJLoader } from 'three/examples/jsm/loaders/OBJLoader'
import {cloneDeep} from 'lodash'
import * as tool from '../lib/tool'

class Client3D {
    constructor(s) {
        this.zoomMax = 520
        this.zoomMin = 50
        this.lastZoom = 0
        this.firstDistance = 0
        this.isDragging = false;
        this.previousMousePosition = {
            x: 0,
            y: 0
        };
        this.cachePosition = {}
        this.container = new THREE.Object3D();
        this.bakGeometrys = {}
        this.designObject3Dchilds = {}
        // 设置旋转速度和方向
        this.speed = 0.025;
        this.direction = 1;
        this.rotationOpen = false
        this.rotationOpenHover = false
        this.modelFormat = ""
        this.rafId = 0
        this.isStopNeedsUpdate = false
        this.contextmenuDown = false
        this.canvasDom = s.canvasDom
        this.canvasWidth = s.canvasWidth || 300
        this.canvasHeight = s.canvasHeight || 300
        this.object3Dchilds = {}
        this.onBeforeCompiles = {}
        this.raycaster = new THREE.Raycaster();
        this.outlinePassTimer = null
        this.modelType = ""
        this.renderCodes = []
        this.mapLoaderCache = {}
        this.playgroudMeshDirLight = null
        this.light_ = null
        this.onOutlinePassSelectedObjects = s.onOutlinePassSelectedObjects
        this.fabricMaps = ["map","normalMap","specularMap","aoMap","displacementMap","roughnessMap","metalnessMap"] //材质固定的5种贴图
        this.initScene()
        this.initCamera()
        // this.initLight()
        
        this.initRender()
        this.initComposer()
    }

    //初始化相机
    initCamera() {
        this.camera = new THREE.PerspectiveCamera(45, this.canvasWidth / this.canvasHeight, 1, 1000);
        this.camera.aspect = this.canvasWidth / this.canvasHeight
        this.camera.zoom = 1.5
        this.camera.updateProjectionMatrix()
        this.scene.add(this.camera)
    }

    //设置摄像机参数
    setCameraParam(fov = 45,zoom = 1.5){
        this.camera.fov = fov
        this.camera.zoom = zoom
        this.camera.updateProjectionMatrix()
    }

    //获取canvasdom
    getCanvasDom() {
        return this.render?.domElement
    }

    //清除场景
    getCameraPosition(){
        return this.camera.position
    }

    //设置场景模
    clearSceneBg(){
        this.scene.background = new THREE.Color(0xFFFFFF)
        // this.scene.fog = new THREE.Fog(0xF9F5F5, 500, 800);
        this.scene.environment = null
        this.scene.backgroundBlurriness = 0
    }

    setSceneBackgroundBlurriness(num = 0){
        this.scene.backgroundBlurriness = num
    }

    initLight()
    {
        // 灯光偏移位置
        const kX = 12;
        const kY = 345;
        const kZ = -400;
        // 灯光强度
        const kIntensity = 0.8;
        const kLightColor = 0xFFFFFF;
        // const kAmbientIntensity = 1.8;
        const kAmbientIntensity = 1.24;
        this.light_ = new THREE.AmbientLight(kLightColor, kAmbientIntensity);
        this.light_.intensity = kAmbientIntensity;
        this.scene.add(this.light_);
        const kLeftScale = 1.3;
        const kRightScale = 1.7;
        const dirLight2 = new THREE.DirectionalLight(kLightColor, kIntensity * kRightScale);
        dirLight2.castShadow = true;
        this.scene.add(dirLight2);
        dirLight2.position.set(-kX, kY, kZ);
        const dirLight4 = new THREE.DirectionalLight(kLightColor, kIntensity * kLeftScale);
        dirLight4.castShadow = true;
        this.scene.add(dirLight4);
        dirLight4.position.set(kX, kY, kZ);
      

        const dirLight5 = new THREE.DirectionalLight(kLightColor, kIntensity * 2.4);
        dirLight5.castShadow = true
        dirLight5.receiveShadow = true
        this.scene.add(dirLight5);
        dirLight5.position.set(kX, kY, -kZ);
        
        // dirLight5.target.position.set(0, 0, 0);

        // window.dirLight2 = dirLight2
        // window.dirLight4 = dirLight4
        // window.dirLight5 = dirLight5


        this.adjustLightShadow(dirLight4);
    }

    adjustLightShadow(light)
    {
        light.castShadow = true;
        const kShadowSize = 2048;
        const kFov = 60;
        const kFar = 700;
        const kNear = 0.1;
        const kD = 1300;
        const kTop = kD;
        const kLeft = -kD;
        const kRight = kD;
        const kBottom = -kD;
        light.shadow.mapSize.set(kShadowSize,kShadowSize);
        light.shadow.bias = -0.002;
        let shadowCamera = light.shadow.camera;
        shadowCamera.fov = kFov;
        shadowCamera.far = kFar;
        shadowCamera.near = kNear;
        shadowCamera.left = kLeft;
        shadowCamera.top = kTop;
        shadowCamera.bottom = kBottom;
        shadowCamera.right = kRight;
        shadowCamera.zoom = 3;
    }

    //设置场景
    setSceneBg(path){
        return new Promise((resolve, reject)=>{
            new RGBELoader().load( path, ( texture ) => {
                texture.mapping = THREE.EquirectangularReflectionMapping;
                this.scene.background = texture;
                this.scene.environment = texture;
                resolve()
            },()=>{},()=>{
                reject()
            })
        })
    }
    
    //移除阴影
    removeShadow(){
        if(this.playgroudMeshDirLight){
            this.scene.remove(this.playgroudMeshDirLight,this.playgroudMesh)
        }
    }

    //添加阴影
    addShadow(y = -0.3){
        // this.scene.background = new THREE.Color(0xC8C8C8)
        // this.scene.fog = new THREE.Fog(0xC8C8C8, 2, 1200);
        // console.log("添加阴影======================")
        // this.playgroudMeshDirLight = new THREE.PointLight(0xffffff, 1);
        // this.playgroudMeshDirLight.position.set(0, 0, 0);
        // this.playgroudMeshDirLight.castShadow = true;
        // this.playgroudMeshDirLight.shadow.mapSize.width = 1200;
        // this.playgroudMeshDirLight.shadow.mapSize.height = 1200;
        // window.playgroudMeshDirLight = this.playgroudMeshDirLight
        // this.scene.add(this.playgroudMeshDirLight)

        // const playgroudMeshDirLight = new THREE.DirectionalLight(0xffffff, 0.3);
        // playgroudMeshDirLight.position.set(-46, 338, -15);
        // // playgroudMeshDirLight.castShadow = true;
        // // playgroudMeshDirLight.shadow.mapSize.width = 1200;
        // // playgroudMeshDirLight.shadow.mapSize.height = 1200;
        // this.scene.add(playgroudMeshDirLight)

        // this.playgroudMeshDirLight = new THREE.PointLight(0xffffff, 100);
        // this.playgroudMeshDirLight.position.set(0, 0, 0);
        // this.playgroudMeshDirLight.castShadow = true;
        // this.playgroudMeshDirLight.shadow.mapSize.width = 1200;
        // this.playgroudMeshDirLight.shadow.mapSize.height = 1200;
        // window.playgroudMeshDirLight = this.playgroudMeshDirLight
        // this.scene.add(this.playgroudMeshDirLight)

        // this.playgroudMesh = new THREE.Mesh(new THREE.PlaneGeometry(800, 800), new THREE.MeshPhongMaterial({ color: 0xcccccc, depthWrite: false }));
        // this.playgroudMesh.rotation.x = - Math.PI / 2;
        // this.playgroudMesh.receiveShadow = true;
        // this.playgroudMesh.position.y = y
        // this.playgroudMesh.position.z = -100
        // this.scene.add(this.playgroudMesh);
    }


    //初始化场景
    initScene() {
        this.scene = new THREE.Scene()

        this.scene.background = new THREE.Color(0xffffff);

        // this.scene.fog = new THREE.Fog(0xffffff, 1, 6);

        this.ambientLight = new THREE.AmbientLight(0xffffff, 0.6)
        this.scene.add(this.ambientLight);

        this.directionalLight_1 = new THREE.DirectionalLight(0xffffff, 0.3);
        this.directionalLight_1.position.set(0, 0, 0.5);
        this.scene.add(this.directionalLight_1);

        this.directionalLight_2 = new THREE.DirectionalLight(0xffffff, 0.3);
        this.directionalLight_2.position.set(0, 0, -0.5);
        this.scene.add(this.directionalLight_2);


        // const dirLight = new THREE.DirectionalLight(0xffffff, 0.1);
        // dirLight.position.set(0, 0, 0);
        // dirLight.shadow.mapSize = new THREE.Vector2(2500, 2500)
        // dirLight.castShadow = true;
        // // dirLight.shadow.camera.top = 180;
        // // dirLight.shadow.camera.bottom = - 100;
        // // dirLight.shadow.camera.left = - 120;
        // // dirLight.shadow.camera.right = 120;
        // this.scene.add(dirLight);





        // const grid: any = new THREE.GridHelper(5, 30, 0x000000, 0x000000);
        // grid.position.y = -0.3
        // grid.material.opacity = 1;
        // grid.material.transparent = true;
        // this.scene.add(grid);

        // const size = 5;
        // const divisions = 10;

        // const gridHelper = new THREE.GridHelper(size, divisions);
        // this.scene.add(gridHelper);

    }

    //初始化渲染
    initRender() {
        this.render = new THREE.WebGLRenderer({
            canvas: this.canvasDom,
            preserveDrawingBuffer: true,
            antialias: true,
            alpha: true
        });
        this.render.setPixelRatio(window.devicePixelRatio);
        this.render.setSize(this.canvasWidth, this.canvasHeight);
        // this.render.shadowMap.enabled = true;
        // this.render.shadowMap.type = THREE.PCFSoftShadowMap;
        this.render.autoClear = true;
        // this.render.physicallyCorrectLights = true;
        // this.render.outputColorSpace = "srgb"
        // this.render.gammaFactor = 2.2;
    }

    //判断是否有hdr场景
    hasScene(){
        return this.scene.background.isTexture || false
    }

    //启动场景
    start() {
        // this.contron = new OrbitControls(this.camera, this.canvasDom);
        // this.contron.enableDamping = true
        // this.contron.enablePan = false
        // this.contron.maxZoom = 4
        // this.contron.minZoom = 1
        // this.contron.maxDistance = 300
        // this.contron.minDistance = 100
        // this.contron.update()
        this.loopRender()
    }

    //设置canvas大小
    setCanvasSize(width = document.body.clientWidth, height = document.body.clientHeight) {
        this.canvasWidth = width
        this.canvasHeight = height
        this.render.setSize(width, height);
        this.camera.aspect = width / height
        this.camera.zoom = 1.5
        this.camera.updateProjectionMatrix()

        this.composer.setSize(width, height);
        this.effectFXAA.uniforms['resolution'].value.set(1 / width, 1 / height);
    }

    //加载子部件并替换
    replaceGeometry(name,path){
        return new Promise((resolve, reject)=>{
            new OBJLoader().load(process.env.REACT_APP_OSS_URL+path,(objects) => {
                this.object3Dchilds[name].geometry.dispose()
                this.object3Dchilds[name].geometry = objects.children[0].geometry
                resolve()
            },()=>{},()=>{reject()})
        })
    }

    //循环渲染
    loopRender() {
        // this.contron?.update();
        this.rafId = requestAnimationFrame(() => {
            this.loopRender()
        })
        if(this.modelObject && this.rotationOpen){
            this.container.rotation.y += this.speed * this.direction;
        }
        this.composer.render();
        // if(this.dirLight && this.shadowMap){
        //     this.render.render(this.scene, this.dirLight.shadow.camera, this.shadowMap);
        // }
        

        //this.render?.render(this.scene as Object3D, this.camera as Camera)
    }

    //旋转
    rotation(open){
        this.rotationOpen = open
    }

    stopNeedsUpdate() {
        this.isStopNeedsUpdate = true
    }

    //清除法线纹理
    clearNormalMap(type = "normalMap", color = "#ffffff") {
        for (let name in this.object3Dchilds) {
            let mesh = this.object3Dchilds[name]
            this.onBeforeCompiles = {}
            mesh.material.onBeforeCompile = () => { }
            mesh.material[type] = null
            mesh.material.color.set(color)
            mesh.material.needsUpdate = true;
            this.object3Dchilds[mesh.name] = mesh
        }
    }

    getObjects(){
        return this.modelObject
    }

    //选择部位效果
    activate(name) {
        //console.log("name", name)
        let object = this.object3Dchilds[name]
        this.outlinePass.selectedObjects = [object];
        this.outlinePass.pulsePeriod = 1
        this.outlinePass.enabled = true
        if(this.outlinePassTimer){
            clearTimeout(this.outlinePassTimer)
            this.outlinePassTimer = null
        }
        if (!this.outlinePassTimer) {
            this.outlinePassTimer = setTimeout(() => {
                this.outlinePass.selectedObjects = []
                this.outlinePassTimer = null
            }, 2000)
        }
    }

    //设置map的repeat
    setMapRepeat(name, repeatNum, repeatNumY = 10) {
        let object = this.object3Dchilds[name]
        if(!object){
            return
        }
        for(let i=0;i<this.fabricMaps.length;i++){
            let map = this.fabricMaps[i]
            if(object.material[map]){
                object.material[map].repeat = new THREE.Vector2(repeatNum, repeatNumY)
            }
        }
        this.object3Dchilds[name] = object
    }

    //设置map的offset
    setMapOffset(name, x,y) {
        let object = this.object3Dchilds[name]
        if(!object){
            return
        }
        for(let i=0;i<this.fabricMaps.length;i++){
            let map = this.fabricMaps[i]
            if(object.material[map]){
                object.material[map].offset = new THREE.Vector2(x,y)
            }
        }
        this.object3Dchilds[name] = object
    }

    //设置置换贴图displacementScale: SCALE,
					//displacementBias: BIAS,
    setDisplacementMapAttr(name, scale, bias) {
        let object = this.object3Dchilds[name]
        if(!object){
            return
        }
        if(object?.material.displacementMap){
            object.material.displacementScale = scale
            object.material.displacementBias = bias
        }
        object.material.needsUpdate = true
        this.object3Dchilds[name] = object
    }
                    

    //设置材质透明
    setMaterialTransparent(name, transparent) {
        let object = this.object3Dchilds[name]
        if(!object){
            return
        }
        object.material.transparent = transparent
        object.material.needsUpdate = true
        this.object3Dchilds[name] = object
    }

    //设置材质颜色
    setMaterialColor(name, color) {
        let object = this.object3Dchilds[name]
        if(!object){
            return
        }
        object.material.color.set(color)
        object.material.needsUpdate = true
        this.object3Dchilds[name] = object
    }

 

    //设置map平铺模式
    openRepeat(name, open){
        let object = this.object3Dchilds[name]
        if(!object){
            return
        }
        for(let i=0;i<this.fabricMaps.length;i++){
            let map = this.fabricMaps[i]
            if(object.material[map]){
                if(open){
                    object.material[map].wrapS = THREE.RepeatWrapping;
                    object.material[map].wrapT = THREE.RepeatWrapping;
                }else{
                    object.material[map].wrapS = THREE.ClampToEdgeWrapping
                    object.material[map].wrapT = THREE.ClampToEdgeWrapping
                }
                object.material[map].needsUpdate = true
            }
        }
        this.object3Dchilds[name] = object
    }

    //clear清除贴图
    clearMap(code){
        let mesh = this.object3Dchilds[code]
        //先清除所有贴图
        for(let i=0;i<this.fabricMaps.length;i++){
            delete mesh?.material[this.fabricMaps[i]]
            mesh.material.needsUpdate = true
        }
    }

    //设置贴图
    setMap(url, type = "normalMap", code = "") {
        return new Promise((resolve, reject) => {
            if(this.mapLoaderCache[url]){
                let mesh = this.object3Dchilds[code]
                if(!mesh){
                    resolve(null)
                    return
                }
                mesh.material[type] = this.mapLoaderCache[url]
                mesh.material.needsUpdate = true
                this.object3Dchilds[code] = mesh
                resolve(null)
                return
            }
            let mesh = this.object3Dchilds[code]
            if(!mesh){
                resolve(null)
                return
            }
            const loader = new THREE.TextureLoader()
            loader.load(process.env.REACT_APP_OSS_URL + url, async (texture) => {
                mesh.material[type] = texture
                mesh.material.needsUpdate = true
                this.object3Dchilds[code] = mesh
                this.mapLoaderCache[url] = texture
                resolve(null)
            }, () => { }, () => {
                reject()
            })
        })
    }

    //判断是否有材质
    hasMap(name){
        if(!name){
            let h = false
            tag:
            for(let i in this.object3Dchilds){
                let m = this.object3Dchilds[i]
                for(let j=0;j<this.fabricMaps.length;j++){
                    if(m.material[this.fabricMaps[j]]){
                        h = true
                        break tag
                    }
                }
            }
            return h
        }
        let object = this.object3Dchilds[name]
        for(let j=0;j<this.fabricMaps.length;j++){
            if(object.material[this.fabricMaps[j]]){
                return true
            }
        }
        return false
    }

    //设置材质颜色
    setMaterialColor(codes, color){
        for(let i = 0; i < codes.length; i++){
            let code = codes[i]
            let mesh = this.object3Dchilds[code]
            mesh.material.color.set(color)
            mesh.material.needsUpdate = true;
            this.object3Dchilds[code] = mesh
        }
    }

    mapUV(geometry)
    {
        // 获取所有顶点的uv坐标
        var uvs = geometry.attributes.uv.array;

        // 初始化最小和最大的uv坐标
        var minU = 1, maxU = 0, minV = 1, maxV = 0;

        // 遍历所有uv坐标，找到最小和最大的u值和v值
        for (var i = 0; i < uvs.length; i += 2) {
            var u = uvs[i];
            var v = uvs[i + 1];
            minU = Math.min(minU, u);
            maxU = Math.max(maxU, u);
            minV = Math.min(minV, v);
            maxV = Math.max(maxV, v);
        }

        // 计算原始uv坐标范围
        var rangeU = maxU - minU;
        var rangeV = maxV - minV;

        // 如果纹理的宽度大于高度
        if (rangeU > rangeV) {
            // 缩放比例
            var scale = 1 / rangeU;
            // 计算空白区域的长度
            var delta = (rangeU - rangeV) / 2;
            // 将所有uv坐标缩放到正方形内
            for (var i = 0; i < uvs.length; i += 2) {
                uvs[i] = (uvs[i] - minU) * scale;
                uvs[i + 1] = (uvs[i + 1] - minV + delta) * scale;
            }
        }
        // 如果纹理的高度大于宽度
        else {
            // 缩放比例
            var scale = 1 / rangeV;
            // 计算空白区域的长度
            var delta = (rangeV - rangeU) / 2;
            // 将所有uv坐标缩放到正方形内
            for (var i = 0; i < uvs.length; i += 2) {
                uvs[i] = (uvs[i] - minU + delta) * scale;
                uvs[i + 1] = (uvs[i + 1] - minV) * scale;
            }
        }

        // 更新BufferGeometry的uv属性
        geometry.attributes.uv.needsUpdate = true;
    }



    action() {
        let _this = this
        return {
            //根据name设置图片Texture
            setMapImageTextureByName(name, url) {
                return new Promise((resolve, reject) => {
                    const loader = new THREE.TextureLoader()
                    const texture = loader.load(url)
                    let object = _this.object3Dchilds[name]
                    object.material.map = texture
                    object.material.map.needsUpdate = true
                    resolve(null)
                })

            },

            //根据name设置mapTexture
            setMapCanvasTextureByName(name, canvas) {
                let object = _this.object3Dchilds[name]
                let texture = new THREE.CanvasTexture(canvas)
                let geometry = object.geometry.clone();
                let designMaterial = object.material.clone();
                texture.minFilter = THREE.LinearFilter;
                // 复制变换操作
                var newPosition = object.position.clone();
                var newRotation = object.rotation.clone();
                var newScale = object.scale.clone();
                
                // console.log("designMaterial.material",designMaterial.material)
                for(let i=0;i<_this.fabricMaps.length;i++){
                    delete designMaterial[_this.fabricMaps[i]]
                }
                // console.log("designMaterialdesignMaterial",designMaterial)
                
                designMaterial.side = THREE.FrontSide;
                designMaterial.dithering = true;
                designMaterial.transparent = true;
                designMaterial.needsUpdate = true;
                designMaterial.map = texture

                if(_this.modelType === "glb"){
                    designMaterial.map.flipY = false
                }
                // designMaterial.map.offsetX = 20
    
                let mesh = new THREE.Mesh(geometry, designMaterial);
                let parent = object.parent;
                mesh.name = 'design_mesh_' + object.name;
                mesh.position.copy(newPosition);
                mesh.rotation.copy(newRotation);
                mesh.scale.copy(newScale);
                // mesh.renderOrder = 1;

                // 使用uv坐标移动到0,1
                //  // 计算UV坐标的范围
                _this.mapUV(geometry)
                parent.add(mesh);
                mesh.castShadow = true;
                mesh.receiveShadow = false;
                _this.designObject3Dchilds[object.name] = mesh
                return {
                    //更新map
                    needsUpdate(timeout = 0) {
                        if (designMaterial) {
                            setTimeout(() => { designMaterial.map.needsUpdate = true }, timeout)
                        }
                    }
                }
            },

            getObjects(){
		        return _this.modelObject
		    }

        }
    }

    //设置摄像机位置
    setCamera(x, y, z) {
        this.camera.position.set(x, y, z)
    }

    setModelMap(name){
        let child = this.object3Dchilds[name]
        let geometry = cloneDeep(child.geometry);
        let designMaterial = cloneDeep(child.material);
        designMaterial.side = THREE.FrontSide;
        designMaterial.dithering = true;
        designMaterial.transparent = true;
        designMaterial.needsUpdate = true; 
        // designMaterial.opacity = 0.5
        let mesh = new THREE.Mesh(geometry, designMaterial);
        let parent = child.children;
        mesh.name = 'm_mesh_' + child.name;
        const loader = new THREE.TextureLoader()
        loader.load("http://resource.moreplay.com.cn/files/a5aa6bc55a77966e6cb37d50f370e842.jpeg",t => {
            mesh.normalMap = t
            mesh.needsUpdate = true;  
        })

        parent.add(mesh);
    }

    

    //加载模型，自动区分格式
    loadModel(path, onProgress) {
        let loader = new OBJLoader()
        if(path.indexOf(".obj") !== -1){
            this.modelType = "obj"
        }else{
            this.modelType = "glb"
            loader = new GLTFLoader()
        }
        return new Promise((resolve, reject) => {
            loader.load(path, async (objects) => {
                if (this.modelType === "glb"){
                    objects = objects.scene
                }
                 //模型包围盒
                let modelBox3 = new THREE.Box3();
                var meshBox3 = new THREE.Box3();
                modelBox3.expandByObject(objects);
                //计算模型的中心点坐标，这个为爆炸中心
                let modelWorldPs = new THREE.Vector3().addVectors(modelBox3.max, modelBox3.min).multiplyScalar(0.5);

                for (let i = 0; i < objects.children.length; i++) {
                    let child = objects.children[i]
                    if (child.isMesh) {
                        meshBox3.setFromObject(child);                   
                        //获取每个mesh的中心点，爆炸方向为爆炸中心点指向mesh中心点
                        let worldPs = new THREE.Vector3().addVectors(meshBox3.max, meshBox3.min).multiplyScalar(0.5);
                        if(isNaN(worldPs.x))return;
                        //计算爆炸方向
                        child.worldDir = new THREE.Vector3().subVectors(worldPs, modelWorldPs).normalize();
                        //保存初始坐标
                        child.userData.oldPs = child.getWorldPosition(new THREE.Vector3())
                        if (!child?.material?.normalMap){
                            child.material = new THREE.MeshPhongMaterial({
                                side: THREE.DoubleSide
                            })
                        }
                        child.castShadow = true;
                        child.receiveShadow = false;
                        this.object3Dchilds[child.name] = child
                    }
                }
                this.modelObject = objects
                // this.scene?.add(objects)

                //将模型添加到容器对象中
                this.container.add(objects);
                this.scene.add(this.container);
                this.setContentCenter(objects)
                resolve(this.action())
                // setTimeout(() => ), 500)
            }, xhr => {
                let p = (xhr.loaded / xhr.total) * 100;
                onProgress(p.toFixed(2))
            }, error => {
                reject(error)
            })
        })

    }

    //销毁
    destroy() {
        this.scene.traverse((obj) => {
            if (obj.type === 'Mesh') {
              obj.geometry.dispose();
              obj.material.dispose();
            }
        })
        this.scene?.remove(this.container)
        this.scene?.remove(this.modelObject)
        // // this.contron?.dispose()
        // this.scene?.dispose()
        this.render.clear("#FFFFFF")
        cancelAnimationFrame(this.rafId)
    }

    //重置模型位置
    resetModelPosition(){
        this.container.rotation.x = this.cachePosition.mx
        this.container.rotation.y = this.cachePosition.my
        this.camera.position.z = this.cachePosition.cz
    }

    //模型垂直居中
    setContentCenter(object) {
        const box = new THREE.Box3().setFromObject(this.container);
        const center = box.getCenter(new THREE.Vector3());
        //点移到几何中心
        object.position.sub(center);
        const boxSize = box.getSize(new THREE.Vector3());
        if (boxSize.x > boxSize.y) {
            this.camera.position.z = boxSize.x * 2.8;
        } else {
            this.camera.position.z = boxSize.y * 2.8;
        }
        this.cachePosition.mx = cloneDeep(this.container.rotation.x)
        this.cachePosition.my = cloneDeep(this.container.rotation.y)
        this.cachePosition.cz = cloneDeep(this.camera.position.z)
    }

    FitCameraToObject(obj, camera)
    {
        //calc cam pos from Bounding Box
        const BB = new THREE.Box3().setFromObject(obj);

        let centerPoint = new THREE.Vector3();
        centerPoint = BB.getCenter(centerPoint);

        let size = new THREE.Vector3();
        size = BB.getSize(size);

        const backupSize = Math.max(size.x, size.y);
        const backup = (backupSize / 2) / Math.sin((camera.fov / 2) * (Math.PI / 180));
        const camZpos = BB.max.z + backup + camera.near;

        //move cam
        camera.position.set(centerPoint.x, centerPoint.y, -camZpos * 1.4);
        camera.far = camera.near + 100 * size.z;
        camera.updateProjectionMatrix();
    }

    //
    setRenderCodes = (codes) => {
        this.renderCodes = codes
    }

    

    //初始化选择部位的阴影效果
    initComposer() {
        this.composer = new EffectComposer(this.render);
        const renderPass = new RenderPass(this.scene, this.camera);
        this.composer.addPass(renderPass);
        this.outlinePass = new OutlinePass(new THREE.Vector2(this.canvasWidth, this.canvasHeight), this.scene, this.camera);
        // this.outlinePass.edgeStrength = 4.6;
        // this.outlinePass.visibleEdgeColor.set("rgb(245, 119, 102)");
        // this.outlinePass.hiddenEdgeColor.set("#5336dc");
        // this.outlinePass.edgeThickness = 4.4
        // this.outlinePass.edgeGlow = 1
        // this.outlinePass.pulsePeriod = 1
        this.outlinePass.edgeStrength = 4;
        this.outlinePass.visibleEdgeColor.set(new THREE.Color(0x1677ff, 1.0, 0));
        this.outlinePass.hiddenEdgeColor.set(new THREE.Color(0x1677ff, 1.0, 0));
        this.outlinePass.edgeThickness = 1
        this.outlinePass.edgeGlow = 1


        this.composer.addPass(this.outlinePass);
        this.effectFXAA = new ShaderPass(FXAAShader);
        this.effectFXAA.uniforms['resolution'].value.set(1 / this.canvasWidth, 1 / this.canvasHeight);
        this.composer.addPass(this.effectFXAA);

        const handleClickDom = (event, t = "") => {
            event.preventDefault()
            this.isDragging = true;
            if(t == "touch"){
                const touches = event.touches
                event.clientX = touches[0].clientX
                event.clientY = touches[0].clientY
                if(touches.length > 1){ //判断是否是两指
                    const events1 = touches[0];
                    const events2 = touches[1];
                    const one = {
                        x:events1.pageX, //第一根手指的横坐标
                        y:events1.pageY, //第一根手指的横坐标
                    }; //第一根手指的横坐标
                    const two = {
                        x:events2.pageX, //第二根手指的横坐标
                        y:events2.pageY, //第二根手指的横坐标
                    }; 
                    this.firstDistance = this.getDistance(one,two);
                    return
                }
            }

            this.previousMousePosition = {
                x: event.clientX,
                y: event.clientY
            };

            
        }

        this.render?.domElement.addEventListener("mousedown", (e) => handleClickDom(e));
        this.render?.domElement.addEventListener("mousemove", (event)=>{
            const bound = this.canvasDom.getBoundingClientRect()
            const mouse = {}
            mouse.x = ((event.clientX - bound.left) / this.canvasWidth) * 2 - 1;
            mouse.y = - ((event.clientY - bound.top)/ this.canvasHeight) * 2 + 1;
            this.raycaster.setFromCamera(mouse, this.camera);
            const intersects = this.raycaster.intersectObject(this.scene, true);
            if (intersects.length > 0) {
                if(this.rotationOpen){
                    this.rotationOpen = false
                    this.rotationOpenHover = true
                }
                const selectedObject = intersects[0].object;
                const selectedObjects = [];
                selectedObjects.push(selectedObject);
                this.outlinePass.selectedObjects = selectedObjects;
                if(this.outlinePassTimer){
                    clearTimeout(this.outlinePassTimer)
                    this.outlinePassTimer = null
                }
                if (!this.outlinePassTimer) {
                    this.outlinePassTimer = setTimeout(() => {
                        this.outlinePass.selectedObjects = []
                        this.outlinePassTimer = null
                    }, 2000)
                }
            } else {
                clearTimeout(this.outlinePassTimer)
                this.outlinePassTimer = null
                if(this.rotationOpenHover){
                    this.rotationOpen = true
                    this.rotationOpenHover = false
                }
                this.outlinePass.selectedObjects = [];
            }
            if(this.onOutlinePassSelectedObjects){
                this.onOutlinePassSelectedObjects(this.outlinePass.selectedObjects)
            }
            if(this.rotationOpen){
                this.rotationOpen = false
                this.rotationOpenHover = true
            } 
            this.mousemoveModelHandle(event)
        });
        this.render?.domElement.addEventListener("mouseup", (e) => {
            e.preventDefault()
            this.isDragging = false;
            if(this.rotationOpenHover){
                this.rotationOpen = true
                this.rotationOpenHover = false
            }
            if(this.contextmenuDown){
                this.contextmenuDown = false
            }
        });

        this.render?.domElement.addEventListener("touchstart", (e) => handleClickDom(e,"touch"));
        this.render?.domElement.addEventListener("touchmove", (event)=>{
            event.preventDefault()
            const touches = event.touches;
            if(touches.length > 1){
                const events1 = touches[0];
                const events2 = touches[1];
                const one = {
                    x:events1.pageX, //第一根手指的横坐标
                    y:events1.pageY, //第一根手指的横坐标
                }; //第一根手指的横坐标
                const two = {
                    x:events2.pageX, //第二根手指的横坐标
                    y:events2.pageY, //第二根手指的横坐标
                }; 
                const distance = this.getDistance(one,two);
                const zoom = distance / this.firstDistance
                this.modelZoom(zoom)
                this.lastZoom = zoom
                return
            }

            event.clientX = touches[0].clientX
            event.clientY = touches[0].clientY
            this.mousemoveModelHandle(event)
        });
        this.render?.domElement.addEventListener("touchend", (e) => {
            e.preventDefault()
            this.isDragging = false;
            if(this.rotationOpenHover){
                this.rotationOpen = true
                this.rotationOpenHover = false
            }
        });

        this.render?.domElement.addEventListener("wheel", (e) => {
            e.preventDefault()
            let evt = e || window.event;
            evt.preventDefault();
            if( evt.deltaY > 0){
                this.modelZoomIn()
            }else{
                this.modelZoomOut()
            }
        }, { passive: false });

        //右键点击
        this.render?.domElement.addEventListener("contextmenu", (e) => {
            e.preventDefault()
            this.contextmenuDown = true
        });
    }

    modelZoomIn(){
        if(!(this.camera.position.z + 1 > this.zoomMin && this.camera.position.z + 1 < this.zoomMax)){
            return
        }
        // this.container.scale.z += 0.1
        // this.container.scale.x += 0.1
        // this.container.scale.y += 0.1
       this.camera.position.z += 1
    }

    modelZoomOut(){
        if(!(this.camera.position.z - 1 > this.zoomMin && this.camera.position.z - 1 < this.zoomMax)){
            return
        }

        // this.container.scale.z -= 0.1
        // this.container.scale.x -= 0.1
        // this.container.scale.y -= 0.1

        this.camera.position.z -= 1
    }

    modelZoom(zoom){
        let step = zoom*5
        if(this.lastZoom <= zoom){
            if(!(this.camera.position.z - step > this.zoomMin && this.camera.position.z - step < this.zoomMax)){
                return
            }
            this.camera.position.z -= step
        }else{
            if(!(this.camera.position.z + step > this.zoomMin && this.camera.position.z + step < this.zoomMax)){
                return
            }
            this.camera.position.z += step
        }
    }

    // 缩放事件的处理
    getDistance(start, stop){ //计算两根手指之间的距离
        return Math.sqrt(Math.pow(Math.abs(start.x - stop.x), 2) + Math.pow(Math.abs(start.y - stop.y), 2));
    };

    //截图
    screePhoto() {
        return new Promise((resolve, reject) => {
            this.render?.domElement.toBlob((file)=>{
                resolve(file)
            })
        })
    }

    //截图base64
    screePhoto64() {
        return new Promise((resolve, reject) => {
            let file = this.render?.domElement.toDataURL()
            resolve(file)
        })
    }

    //模型分解
    applyScalar(scalar = 0.2) {
        //爆炸公式
        for (let i = 0; i < this.modelObject.children.length; i++) {
            let value = this.modelObject.children[i]
            if(!value.isMesh || !value.worldDir) continue;
            value.position.copy(new THREE.Vector3().copy(value.userData.oldPs).add(new THREE.Vector3().copy(value.worldDir).multiplyScalar(scalar)))
        }
    }


    isWithinMaxAngle(x)
    {
        if(x < -0.7){
            return false
        }
        if(x > 1){
            return false
        }
        return true
    }

    mousemoveModelHandle(event){
        // 如果没有按下鼠标，则退出函数
        if (!this.isDragging) {
            return;
        }
        // 计算鼠标移动的距离
        var deltaMove = {
            x: Math.sign(event.clientX - this.previousMousePosition.x),
            y: Math.sign(event.clientY - this.previousMousePosition.y)
        };
        
        if(!this.contextmenuDown){
            let rotation_speed_ = 0.05;
            if (!this.isWithinMaxAngle(deltaMove.y * rotation_speed_ + this.container.rotation.x)){
                return
            }
            // 将模型绕Y轴旋转
            this.container.rotation.y += deltaMove.x * rotation_speed_;
            // 将模型绕X轴旋转
            this.container.rotation.x += deltaMove.y * rotation_speed_;
        }else{ //右键移动
            this.container.position.y += deltaMove.y * -1;
            this.container.position.x += deltaMove.x * 1;
        }
        
        // 更新上一次鼠标位置
        this.previousMousePosition = {
            x: event.clientX,
            y: event.clientY
        };

    }

}

export default Client3D